﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using zeus.Core;
using zeus.Core.RepositoryInterfaces;
using SharpArch.Data.NHibernate;
using SharpArch.Core.PersistenceSupport;
using NHibernate;
using NHibernate.Transform;
using NHibernate.Criterion;
using SharpArch.Core;

namespace zeus.Data
{
    public class UsuarioRepository : Repository<Usuario>, IUsuarioRepository
    {

        private readonly IRepository<Reporte> reporteRepository;

        public UsuarioRepository(IRepository<Reporte> reporteRepository)
        {
            Check.Require(reporteRepository != null, "reporteRepository may not be null");
            this.reporteRepository = reporteRepository;
        }


        public bool UsuarioDuplicado(Usuario usuario)
        {
            Usuario usuarioDuplicado = Session.CreateSQLQuery("select * from usuario where usr_login = :cli_login")
                    .AddEntity(typeof(Usuario))
                    .SetAnsiString("cli_login", usuario.Login)
                    .UniqueResult<Usuario>();

            if (usuarioDuplicado == null) return false;

            if (usuarioDuplicado.Id == usuario.Id) return false;

            return true;
        }

        public IList<Usuario> GetByCliente(int ClienteID)
        {            
            return Session.CreateSQLQuery("select * from usuario where cli_id = :cli_id")
                    .AddEntity(typeof(Usuario))
                    .SetInt32("cli_id", ClienteID)
                    .List<Usuario>();
        }
               

        public IList<Grupo> GetDisponiblesByGrupo(int ClienteID, PlanCliente planCliente)
        {
            return Session.CreateSQLQuery("select * from grupo where cli_id = :cli_id and not exists (select 1 from plan_disponible where placli_id = :placli_id and grupo.grp_id = plan_disponible.grp_id)")
                    .AddEntity(typeof(Grupo))
                    .SetInt32("cli_id", ClienteID)
                    .SetInt32("placli_id", planCliente.Id)
                    .List<Grupo>();
        }

        public IList<Grupo> GetSeleccionadosByGrupo(int ClienteID, PlanCliente planCliente)
        {
            return Session.CreateSQLQuery("select * from grupo where cli_id = :cli_id and exists (select 1 from plan_disponible where placli_id = :placli_id and grupo.grp_id = plan_disponible.grp_id)")
                    .AddEntity(typeof(Grupo))
                    .SetInt32("cli_id", ClienteID)
                    .SetInt32("placli_id", planCliente.Id)
                    .List<Grupo>();
        }

        public IList<Usuario> GetDisponiblesByUnidad(int ClienteID, Unidad unidad)
        {
            return Session.CreateSQLQuery("select * from usuario where cli_id = :cli_id and not exists (select 1 from usuario_unidad where und_id = :und_id and usuario.usr_id = usuario_unidad.usr_id)")
                    .AddEntity(typeof(Usuario))
                    .SetInt32("cli_id", ClienteID)
                    .SetInt32("und_id", unidad.Id)
                    .List<Usuario>();
        }

        public IList<Usuario> GetSeleccionadosByUnidad(int ClienteID, Unidad unidad)
        {
            return Session.CreateSQLQuery("select * from usuario where cli_id = :cli_id and exists (select 1 from usuario_unidad where und_id = :und_id and usuario.usr_id = usuario_unidad.usr_id)")
                    .AddEntity(typeof(Usuario))
                    .SetInt32("cli_id", ClienteID)
                    .SetInt32("und_id", unidad.Id)
                    .List<Usuario>();
        }

        public IList<Usuario> GetDisponiblesByGrupo(int ClienteID, Grupo grupo)
        {
            return Session.CreateSQLQuery("select * from usuario where cli_id = :cli_id and not exists (select 1 from grupo_usuario where grp_id = :grp_id and usuario.usr_id = grupo_usuario.usr_id)")
                    .AddEntity(typeof(Usuario))
                    .SetInt32("cli_id", ClienteID)
                    .SetInt32("grp_id", grupo.Id)
                    .List<Usuario>();            
        }

        public IList<Usuario> GetSeleccionadosByGrupo(int ClienteID, Grupo grupo)
        {
            return Session.CreateSQLQuery("select * from usuario where cli_id = :cli_id and exists (select 1 from grupo_usuario where grp_id = :grp_id and usuario.usr_id = grupo_usuario.usr_id)")
                    .AddEntity(typeof(Usuario))
                    .SetInt32("cli_id", ClienteID)
                    .SetInt32("grp_id", grupo.Id)
                    .List<Usuario>();
        }

        public bool IsInRole(string userName, string roles)
        {
            Dictionary<string, object> filtro = new Dictionary<string, object>();
            filtro.Add("Login", userName);

            Usuario usuario = FindOne(filtro);
            if (usuario == null) return false;

            string[] rol = roles.Split(',');

            foreach (string item in rol)
            {
                if (item.Equals(usuario.Rol))
                    return true;
            } 
                        
            return false;
        }

        /// <summary>
        /// Devuelve todos los reportes asignados a un usuario
        /// </summary>
        /// <param name="usuario"></param>
        /// <returns></returns>
        public List<int> GetReportes(Usuario usuario)
        {
            IList<Reporte> reportes = Session.CreateSQLQuery("select * from reporte where rpt_activo = 1 and exists (select 1 from usuario_reporte where usr_id = :usr_id and rpt_estado = 1 and reporte.rpt_id = usuario_reporte.rpt_id)")
                    .AddEntity(typeof(Reporte))
                    .SetInt32("usr_id", usuario.Id)
                    .List<Reporte>();

            List<int> codigos = new List<int>();
            reportes.ToList().ForEach(p => codigos.Add(p.Id));

            return codigos;
        }

        /// <summary>
        /// Determina si un usuario tiene asignado un reporte
        /// </summary>
        /// <param name="usuario"></param>
        /// <param name="codigoReporte"></param>
        /// <returns></returns>
        public bool TieneReporte(Usuario usuario, int codigoReporte)
        {
            List<int> reportes = GetReportes(usuario);
            return reportes.Contains(codigoReporte);
        }

                
        public void InsertOrUpdateReporte(Usuario usuario, int codigoReporte, bool seleccionado)
        {
            bool existe = false;

            foreach (var usuarioReporte in usuario.UsuarioReportes)
                if (usuarioReporte.Reporte.Id == codigoReporte)
                {
                    existe = true;
                    usuarioReporte.Estado = seleccionado;
                }

            if (!existe)
                usuario.AddReporte(new UsuarioReporte()
                {
                    Reporte = reporteRepository.Get(codigoReporte),
                    Estado = seleccionado
                });
                        
        }

        public void DeleteAllPlanDisponible(PlanCliente planCliente)
        {
            // Eliminar todos los usuarios
            foreach (var item in planCliente.PlanesDisponibles)
            {
                Session.Delete(item);
            }

            planCliente.PlanesDisponibles.Clear();
            Session.Flush();
        }

    }
}
